﻿using Max.PH4_2102A.Shopping.DAL;
using Max.PH4_2102A.Shopping.Domain;
using Max.PH4_2102A.Shopping.DTO;
using Max.PH4_2102A.Shopping.IRespository;
using Max.PH4_2102A.Shopping.IService;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Max.PH4_2102A.Shopping.Service
{
    public class OrderMasterService : IOrderMasterService
    {

        //直接用EF的对象来实现事务
        EFCoreHelper _ef;

        //用工作单元实现事务
        IUnitOfWork _unitOfWor;
        IOrderMasterRespository _masterRespository;
        IOrderDetailRespository _detailRespository;
        ISKURespository _skuRespository;


        ILogisticDetailRespository _logisticDetailRespository;
        ILogisticMasterRespository _logisticMasterRespository;

        public OrderMasterService(EFCoreHelper ef, IUnitOfWork unitOfWor, IOrderMasterRespository masterRespository, IOrderDetailRespository detailRespository, ISKURespository skuRespository, ILogisticDetailRespository logisticDetailRespository, ILogisticMasterRespository logisticMasterRespository)
        {
            _ef = ef;
            _unitOfWor = unitOfWor;
            _masterRespository = masterRespository;
            _detailRespository = detailRespository;
            _skuRespository = skuRespository;
            _logisticDetailRespository = logisticDetailRespository;
            _logisticMasterRespository = logisticMasterRespository;
        }


        #region 20230803 three week exam

        /// <summary>
        /// 所有的数据
        /// </summary>
        /// <param name="orderNo">订单号</param>
        /// <param name="name">商品名称</param>
        /// <param name="state">状态</param>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">页码</param>
        /// <param name="total">总记录数</param>
        public dynamic GetOrderData(string orderNo, string name, int state,
            int pageIndex, int pageSize, out int total)
        {
            //1、要找商品名称，所以需要先找订单明细表中的商品名称
            var orders = _detailRespository.GetAll()
               .Where(x => x.Name.Contains(name ?? ""))
               .Where(x => x.OrderNo.Contains(orderNo ?? "")).ToList()
               .DistinctBy(x => x.OrderNo);
            //.Select(x => new { x.OrderNo});

            //2、根据商品名称，找到哪些订单下面有这个商品，然后根据这些订单号去获取订单的具体的信息
            var q = from a in orders
                    join b in _masterRespository.GetAll() on a.OrderNo equals b.OrderNo
                    select new
                    {
                        #region 订单主表字段

                        b.OrderNo,
                        b.RecivedAddress,
                        b.RecivedName,
                        b.RecivedPhone,
                        b.OrderAmount,
                        b.PayAmount,
                        b.PayTime,
                        b.PayType,
                        b.OrderState,
                        OrderStateName = b.OrderState.ToString(),
                        OrderTime = b.OrderTime.ToString("yyyy-MM-dd hh:mm:ss"),

                        #endregion

                        #region 订单对应的商品明细
                        products = _detailRespository.GetAll().Where(x => x.OrderNo.Equals(b.OrderNo)).ToList()
                        #endregion
                    };

            if (state >= 0)
            {
                q = q.Where(x => (int)x.OrderState == state);
            }

            total = q.Count();

            q = q.Skip((pageIndex - 1) * pageSize).Take(pageSize);

            return q;
        }


        //通过订单号获取订单信息、订单商品信息、订单物流信息
        public dynamic GetOrderDetailAndLogistic(string orderNo)
        {
            //一个订单对应多个商品  ---- 之间通过订单号关联
            //一个订单对应一个快递单号 ---- 之间通过订单号关联
            //一个快递单号有多个记录明细 ---- 之间通过快递号关联

            var q = _masterRespository.GetAll()
                        .Where(x => x.OrderNo.Equals(orderNo))
                        .Select(x => new
                        {
                            x.OrderNo,
                            x.OrderAmount,
                            x.OrderState,
                            OrderStateName = x.OrderState.ToString(),
                            OrderTime = x.OrderTime.ToString("yyyy-MM-dd hh:mm:ss"),
                            x.PayAmount,
                            PayTime = x.PayTime == null ? "":Convert.ToDateTime(x.PayTime).ToString("yyyy-MM-dd hh:mm:ss"),
                            x.PayType,
                            x.RecivedAddress,
                            x.RecivedName,
                            x.RecivedPhone,

                            //订单对应的商品
                            products = _detailRespository.GetAll()   //所以订单明细数据
                                        .Where(k => k.OrderNo.Equals(x.OrderNo)).ToList(),  //在所有的明细数据中，找出订单号对就在的数据
                            //订单对应的物流明细
                            logistics =
                                (
                                    from a in _logisticMasterRespository.GetAll() 
                                    join b in _logisticDetailRespository.GetAll() on a.LogisticNo equals b.LogisticNo
                                    where a.OrderNo.Equals(x.OrderNo)
                                    orderby b.StateTime descending
                                    select new { 
                                        StateTime = b.StateTime == null ? "" : Convert.ToDateTime(b.StateTime).ToString("yyyy-MM-dd hh:mm:ss"),
                                        b.Content
                                    }
                                ).ToList()

                        })
                        .FirstOrDefault();


            return q;

            #region EF同步上面操作

            //var _q = _ef.OrderMasters.Where(x => x.OrderNo.Equals(orderNo))
            //     .Select(x => new
            //     {
            //         x.OrderNo,
            //         x.OrderAmount,
            //         x.OrderState,
            //         x.OrderTime,
            //         x.PayAmount,
            //         x.PayTime,
            //         x.PayType,
            //         x.RecivedAddress,
            //         x.RecivedName,
            //         x.RecivedPhone,
            //         products = _ef.OrderDetails.Where(k => k.OrderNo.Equals(x.OrderNo)).ToList()
            //     })
            //    .FirstOrDefault();

            #endregion
        }

        //通过枚举的值，获取对应的名称
        private string GetOrderStateName(OrderStateEnum state)
        {
            return "";
        }


        //查询统计订单销售金额

        public dynamic GetOrderSaleAmount()
        {
            var q = _masterRespository.GetAll().Where(x => x.OrderTime.Month == System.DateTime.Now.Month)
                    .Select(x => new {
                        OrderTime = x.OrderTime.ToString("yyyy-MM-dd"),
                        x.OrderAmount
                    });
            var x = q.Select(x => x.OrderTime);
            var d = q.Select(x => x.OrderAmount);

            return new { x, d };
        }

        #endregion

        #region 订单显示

        /// <summary>
        /// 获取所有订单数据列表
        /// </summary>
        /// <returns></returns>
        public IQueryable<OrderOuputDto> GetOrderList(string orderNo)
        {
            var list = _masterRespository.GetAll().Where(x => x.OrderNo.Contains(orderNo ?? "")).Select(x => new OrderOuputDto
            {
                OrderAmoun = x.OrderAmount,
                OrderNo = x.OrderNo,
                PayTime = x.PayTime,
                PayAmount = x.PayAmount,
                MemberId = x.MemberId,
                OrderStateName = x.OrderState.ToString(),
                OrderState = ((int)x.OrderState).ToString(),
                RateAmount = x.RateAmount,
                OrderTime = x.OrderTime.ToString("yyyy-MM-dd hh:mm:ss"),
                Children = _detailRespository.GetAll()
                                    .Where(p => p.OrderNo.Equals(x.OrderNo))
                                    .Select(p => new OrderDetailOutputDto
                                    {
                                        Image = "66.png",
                                        Number = p.Number,
                                        Price = p.Price,
                                        SKUId = p.SKUId
                                    }).ToList()

            });
            return list;
        }


        public dynamic GetOrderAll(string orderNo, int state, int pageIndex, int pageSize, out int total)
        {
            //所有的订单数据
            var list = _masterRespository.GetAll().Where(x => x.OrderNo.Contains(orderNo ?? ""));
            if (state > 0)
            {
                list = list.Where(x => (int)x.OrderState == state);
            }
            total = list.Count();  //订单的总条数

            list = list.Skip((pageIndex - 1) * pageSize).Take(pageSize); //对订单进行分页

            //查订单对应的商品信息
            var q = from a in list
                    select new
                    {
                        a.Id,
                        a.OrderState,
                        a.MemberId,
                        a.OrderAmount,
                        a.OrderNo,
                        a.OrderTime,
                        a.RateAmount,
                        a.PayAmount,
                        a.PayTime,
                        a.PayType,
                        //订单对应的商品信息
                        products = _detailRespository.GetAll().Where(p => p.OrderNo.Equals(a.OrderNo)).ToList()
                    };
            return q;
        }

        #endregion

        #region 订单添加


        /*
         * 添加订单：是有主表信息和明细表信息（主是商品信息）
         * 
         * **/

        /// <summary>
        /// EF+DTO创建订单
        /// </summary>
        public void CreateOrderByDto(OrderInputDto dto)
        {

            using (var tran = _ef.Database.BeginTransaction())  //开启事务
            {
                try
                {

                    //要添加订单 --- 操作的是订单主表
                    //  --- 暂时没有这个Ordermaster表对象，所以直接new了一个
                    //而我的传的数据都在DTO中，所以需要将dto的数据拿出给到这个实体对象
                    var master = new OrderMasterEntity();

                    #region 手动将DTO的数据传输给实体 -- 订单主表信息

                    master.OrderAmount = dto.OrderAmount;
                    master.RecivedAddress = dto.RecivedAddress;
                    master.RecivedPhone = dto.RecivedPhone;
                    master.RecivedName = dto.RecivedName;
                    master.MemberId = dto.MemberId;
                    master.OrderTime = System.DateTime.Now;
                    master.RateAmount = dto.RateAmount;
                    master.SendType = dto.SendType;
                    #endregion

                    _ef.OrderMasters.Add(master);


                    //要添加订单对应的商品 --- 操作的是订单明细表(多个商品，所以会有多条记录)
                    // ---- 暂时没有这个OrderDetailr表对象，所以直接new了一个。因为是多个商品，所以直接new一个list
                    var details = new List<OrderDetailEntity>();
                    #region 手动将DTO的数据传输给实体--订单商品明细
                    dto.details.ForEach(x =>
                    {
                        details.Add(new OrderDetailEntity
                        {
                            Number = x.Number,
                            OrderNo = master.OrderNo,
                            Price = x.Price,
                            SKUId = x.SKUId
                        });
                    });
                    #endregion
                    _ef.OrderDetails.AddRange(details);

                    _ef.SaveChanges();

                    tran.Commit();  //提交事务
                }
                catch (Exception)
                {
                    tran.Rollback();  //回滚事务
                    throw;
                }
            }
        }


        /// <summary>
        /// 用工作单元实现创建订单
        /// </summary>
        /// <param name="dto"></param>
        public void CreateOrderByUnitOfWork(OrderInputDto dto)
        {
            using (var tran = _unitOfWor.GetDbContext().Database.BeginTransaction())
            {
                try
                {
                    //添加订单
                    var master = new OrderMasterEntity();
                    #region 手动将DTO的数据传输给实体 -- 订单主表信息

                    master.OrderAmount = dto.OrderAmount;
                    master.RecivedAddress = dto.RecivedAddress;
                    master.RecivedPhone = dto.RecivedPhone;
                    master.RecivedName = dto.RecivedName;
                    master.MemberId = dto.MemberId;
                    master.OrderTime = System.DateTime.Now;
                    master.RateAmount = dto.RateAmount;
                    master.SendType = dto.SendType;
                    #endregion
                    _masterRespository.Insert(master);

                    //添加订单明细
                    var details = new List<OrderDetailEntity>();
                    #region 手动将DTO的数据传输给实体--订单商品明细
                    dto.details.ForEach(x =>
                    {
                        details.Add(new OrderDetailEntity
                        {
                            Number = x.Number,
                            OrderNo = master.OrderNo,
                            Price = x.Price,
                            SKUId = x.SKUId
                        });
                    });
                    #endregion
                    _detailRespository.Insert(details);

                    #region 修改可用库存和锁定商品库存
                    /*
                     * 商品的可用库存减少
                     * 商品的锁定库存增加
                     * **/

                    //只修改订单中购买的商品的库存
                    details.ForEach(x =>
                    {

                        bool flag = false;
                        do
                        {
                            //从sku表中，找到订单中的这个商品
                            var m = _skuRespository.GetAll().Where(s => s.Id == x.SKUId).FirstOrDefault();
                            if (m != null)
                            {
                                if (m.ValidStock > x.Number)  //库存和购买的数量进行判断
                                {
                                    m.ValidStock -= x.Number; //可用库存减少
                                    m.LockStock += x.Number; //锁定库存增加
                                }
                            }
                            try
                            {
                                _skuRespository.Update(m);
                            }
                            catch (Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException ex)  //数据版本不致，就会报DbUpdateConcurrencyException异常
                            {
                                flag = true;
                                throw;
                            }

                        } while (true);

                    });

                    #endregion


                    _unitOfWor.SaveChanges();
                    tran.Commit();
                }
                catch (Exception)
                {
                    tran.Rollback();
                    throw;
                }
            }
        }

        /// <summary>
        /// 不用DTO，直接用实体
        /// </summary>
        /// <param name="master"></param>
        /// <param name="details"></param>
        public void CreateOrderByEntity(OrderMasterEntity master, List<OrderDetailEntity> details)
        {

            using (var tran = _ef.Database.BeginTransaction())//开启事务
            {
                try
                {
                    _ef.OrderMasters.Add(master);
                    _ef.OrderDetails.AddRange(details);
                    _ef.SaveChanges();

                    tran.Commit(); //事务提交
                }
                catch (Exception)
                {
                    tran.Rollback();//事务回滚
                    throw;
                }
            }
        }

        #endregion

        #region 退款操作

        //remark：把一个订单的商品全部都退掉
        /// <summary>
        /// 退一个订单的商品(有可能会有多个商品)        
        /// </summary>
        public void BackProduct(string orderNo, string resson, string type)
        {
            using (var tran = _ef.Database.BeginTransaction())
            {
                try
                {
                    //问：修改谁的状态？ ---- 明细表中，这个订单对应的所有商品的状态
                    //1、先找出这个订单的所有商品
                    var products = _ef.OrderDetails.Where(x => x.OrderNo.Equals(orderNo)).ToList();

                    #region 订单明细表：修改状态


                    //2、修改这个订单的所有商品的状态
                    products.ForEach(x =>
                    {
                        x.State = "1";  //0表示正常，1表示退货
                    });


                    #endregion
                    _ef.OrderDetails.UpdateRange(products);

                    #region 退款主表（暂时只用一个表实现）：添加（订单的商品）

                    //退回的商品明细
                    var backProducts = new List<OrderBackMasterProduct>();

                    var backNo = Guid.NewGuid().ToString("N");
                    products.ForEach(x =>
                    {
                        backProducts.Add(new OrderBackMasterProduct
                        {
                            BackAmount = x.Price,
                            BackNo = backNo,
                            OrderNo = orderNo,
                            SKUId = x.SKUId,
                            Number = x.Number,
                            Price = x.Price,
                            BackReason = resson,
                            BackType = type
                        });
                    });


                    #endregion
                    _ef.OrderBackMasters.AddRange(backProducts);

                    _ef.SaveChanges();

                    tran.Commit();
                }
                catch (Exception)
                {
                    tran.Rollback();
                    throw;
                }
            }
        }

        #endregion


    }
}
